package org.example.compare.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import org.example.compare.dto.DateWorkTime;
import org.example.compare.dto.WorkTimeDto;
import org.example.compare.global.SchData;
import org.example.compare.service.THolidayService;
import org.example.compare.util.TimeUtil;

import java.sql.Time;
import java.util.*;

public class THolidayServiceImpl implements THolidayService {
    private static final int DAY = 60 * 60 * 24 * 1000;
    public static List<DateWorkTime> dateWorkTimeList = new ArrayList<>();
    Set<Date> mSetHoliday = new HashSet<>(); // 节假日集合
    // 每周上班时间段，key 0-6表示星期一到星期天
    public Map<Integer, List<WorkTimeDto>> mHashNormalDayToWorkTime = SchData.mHashNormalDayToWorkTime;

    static class TFullTime {
        WorkTimeDto mWorkTimeDto = new WorkTimeDto();
        boolean mbFlag;// 是否为上班时间
    }

    @Override // 计算时间内的总工作时间
    public int diffSeconds(Date rStartDateTime, Date rEndDateTime) {
        if (rStartDateTime.after(rEndDateTime)) {
            return 0;
        }

        Map<Date, List<WorkTimeDto>> hashDateToWorkTime = new HashMap<>();
        capDateWorkTime(rStartDateTime, rEndDateTime, hashDateToWorkTime);

        long iDiffDays = TimeUtil.diffDay(rStartDateTime, rEndDateTime);
        if (iDiffDays == 0) {// 今天与交期同一天
            return sameDayLeftSeconds(rEndDateTime, getTime(rStartDateTime), getTime(rEndDateTime), hashDateToWorkTime);
        } else {
            int iLeftWorkTime = 0;
            iLeftWorkTime += todayLeftSeconds(new Date(rStartDateTime.getYear(), rStartDateTime.getMonth(), rStartDateTime.getDate()), new Time(rStartDateTime.getTime() % DAY), hashDateToWorkTime);
            iLeftWorkTime += finalLeftSeconds(new Date(rEndDateTime.getYear(), rEndDateTime.getMonth(), rEndDateTime.getDate()), new Time(rEndDateTime.getTime() % DAY), hashDateToWorkTime);
            for (int i = 1; i < iDiffDays; ++i) {
                Date date = DateUtil.offsetDay(rStartDateTime, i);
                Date curDate = new Date(date.getYear(), date.getMonth(), date.getDate());
                if (!hashDateToWorkTime.containsKey(curDate)) {
                    continue;
                }
                List<WorkTimeDto> rVecWorkTimeDto = hashDateToWorkTime.get(curDate);
                if (rVecWorkTimeDto.isEmpty()) {
                    iLeftWorkTime += 0;
                } else {
                    iLeftWorkTime += todayLeftSeconds(curDate, rVecWorkTimeDto.get(0).mWorkStartTime, hashDateToWorkTime);
                }
            }
            return iLeftWorkTime;
        }
    }

    // 获取每日工作时间段
    public boolean capDateWorkTime(Date rStartDate, Date rEndDate, Map<Date, List<WorkTimeDto>> rHashDayToWorkTime) {
        if (rEndDate.before(rStartDate)) {
            return false;
        }

        dateWorkTimeList.forEach(workTime -> {
            List<WorkTimeDto> list = rHashDayToWorkTime.getOrDefault(workTime.getAppointedDate(), new ArrayList<>());
            WorkTimeDto workTimeDto1 = new WorkTimeDto();
            workTimeDto1.update(TimeUtil.toTime(workTime.getWorkTimeStart()), TimeUtil.toTime(workTime.getWorkTimeEnd()));
            list.add(workTimeDto1);
            rHashDayToWorkTime.put(workTime.getAppointedDate(), list);
        });

        // capHoliday(rStartDate, rEndDate);

        long iTotalDays = DateUtil.between(rStartDate, rEndDate, DateUnit.DAY) + 1;
        for (int i = 0; i < iTotalDays; ++i) {
            Date date = DateUtil.offsetDay(rStartDate, i);
            Date curDate = new Date(date.getYear(), date.getMonth(), date.getDate());
            if (!rHashDayToWorkTime.containsKey(curDate)) {     // 在指定日期中找不到
                if (!mSetHoliday.contains(curDate)) {   // 在放假日期中找不到
                    int iDayIndex = DateUtil.dayOfWeek(curDate) - 1;
                    if (iDayIndex == 0) {
                        iDayIndex = 7;
                    }
                    if (mHashNormalDayToWorkTime.containsKey(iDayIndex)) {
                        rHashDayToWorkTime.put(curDate, mHashNormalDayToWorkTime.get(iDayIndex));
                    }
                }
            }
        }
        return true;
    }

    public int sameDayLeftSeconds(Date rDate, Time rCurTime, Time rFinalTime, Map<Date, List<WorkTimeDto>> rDateToWorkTime) {
        if (!rDateToWorkTime.containsKey(rDate)) {
            return 0;
        }
        return oneDayLeftSeconds(rDateToWorkTime.get(rDate), rCurTime, rFinalTime);
    }

    public int oneDayLeftSeconds(List<WorkTimeDto> rVecWorkTimeDto, Time rStartTime, Time rEndTime) {
        if (rEndTime.before(rStartTime)) {
            return 0;
        }
        List<TFullTime> vecFullTime = new ArrayList<>();
        for (int i = 0; i < rVecWorkTimeDto.size(); ++i) {
            Time timeStart;
            Time timeEnd;
            if (0 == i) {
                timeStart = new Time(0, 0, 0);
            } else {
                timeStart = rVecWorkTimeDto.get(i - 1).mWorkEndTime;
            }

            TFullTime segTime1 = new TFullTime();
            TFullTime segTime2 = new TFullTime();
            segTime1.mWorkTimeDto.update(timeStart, rVecWorkTimeDto.get(i).mWorkStartTime);
            segTime1.mbFlag = false;
            segTime2.mWorkTimeDto = rVecWorkTimeDto.get(i);
            segTime2.mbFlag = true;
            vecFullTime.add(segTime1);
            vecFullTime.add(segTime2);
            if (rVecWorkTimeDto.size() - 1 == i) {
                timeEnd = new Time(23, 59, 59);
                TFullTime segTime3 = new TFullTime();
                segTime3.mWorkTimeDto.update(rVecWorkTimeDto.get(i).mWorkEndTime, timeEnd);
                segTime3.mbFlag = false;
                vecFullTime.add(segTime3);
            }
        }
        for (int i = 0; i < vecFullTime.size(); ++i) {
            // qDebug() << CCommon::ToString(vecFullTime[i].mWorkTime.mWorkStartTime) << " " << CCommon::ToString(vecFullTime[i].mWorkTime.mWorkEndTime);
            if (TimeUtil.compareTime(rStartTime, vecFullTime.get(i).mWorkTimeDto.mWorkStartTime) != -1 && TimeUtil.compareTime(rStartTime, vecFullTime.get(i).mWorkTimeDto.mWorkEndTime) != 1) {// 找到起点所在区间
                int iValidStartIndex = -1;
                Time realStartTime = rStartTime;
                if (!vecFullTime.get(i).mbFlag) {// 起点在休息区间
                    if (i == vecFullTime.size() - 1) {// 最后一个休息区，则没有工作时间
                        return 0;
                    } else {
                        if (TimeUtil.compareTime(rEndTime, vecFullTime.get(i).mWorkTimeDto.mWorkStartTime) != -1 && TimeUtil.compareTime(rEndTime, vecFullTime.get(i).mWorkTimeDto.mWorkEndTime) != 1) {// 开始与结束都在休息区
                            return 0;
                        } else {// 说明至少有工作时间
                            iValidStartIndex = i + 1;// 真正工作区间
                            realStartTime = vecFullTime.get(iValidStartIndex).mWorkTimeDto.mWorkStartTime;// 更新实际开始时间
                        }
                    }
                } else {
                    iValidStartIndex = i;// 实际开始时间就是rStartTime
                }
                int iValidEndIndex = -1;
                Time realEndTime = rEndTime;
                for (int j = iValidStartIndex; j < vecFullTime.size(); ++j) {
                    if (TimeUtil.compareTime(rEndTime, vecFullTime.get(i).mWorkTimeDto.mWorkStartTime) != -1 && TimeUtil.compareTime(rEndTime, vecFullTime.get(i).mWorkTimeDto.mWorkEndTime) != 1) {
                        if (vecFullTime.get(j).mbFlag) {// 在工作区间
                            iValidEndIndex = j;
                        } else {// 在休息区间
                            iValidEndIndex = j - 1;
                            realEndTime = vecFullTime.get(iValidEndIndex).mWorkTimeDto.mWorkEndTime;
                        }
                        break;
                    }
                }
                int iFreeTime = 0;
                for (int k = iValidStartIndex; k <= iValidEndIndex; ++k) {
                    if (!vecFullTime.get(k).mbFlag) {
                        iFreeTime += TimeUtil.betweenTime(vecFullTime.get(k).mWorkTimeDto.mWorkStartTime, vecFullTime.get(k).mWorkTimeDto.mWorkEndTime);
                    }
                }
                int iWorkTime = TimeUtil.betweenTime(realStartTime, realEndTime);
                iWorkTime -= iFreeTime;
                return iWorkTime;
            }
        }
        return 0;
    }

    private Time getTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);
        return new Time(hour, minute, second);
    }

    // 当天剩余的时间
    public int todayLeftSeconds(Date rDate, Time rCurTime, Map<Date, List<WorkTimeDto>> rDateToWorkTime) {
        if (!rDateToWorkTime.containsKey(rDate)) {
            return 0;
        }
        List<WorkTimeDto> rVecWorkTimeDto = rDateToWorkTime.get(rDate);
        return oneDayLeftSeconds(rVecWorkTimeDto, rCurTime, rVecWorkTimeDto.get(rVecWorkTimeDto.size() - 1).mWorkEndTime);
    }

    // 当天开始到finalTime的时间
    public int finalLeftSeconds(Date rDate, Time rFinalTime, Map<Date, List<WorkTimeDto>> rDateToWorkTime) {
        if (!rDateToWorkTime.containsKey(rDate)) {
            return 0;
        }
        List<WorkTimeDto> rVecWorkTimeDto = rDateToWorkTime.get(rDate);
        if (rVecWorkTimeDto.isEmpty()) {
            return 0;
        }
        return oneDayLeftSeconds(rVecWorkTimeDto, rVecWorkTimeDto.get(0).mWorkStartTime, rFinalTime);
    }
}
